package com.pervasive.services;
 
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletContext;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;

import com.pervasive.container.ContainerStruc;
import com.pervasive.container.GameContainer;
import com.pervasive.mqtt.MQTTConnection;
import com.pervasive.project.unified.data.constants.Constants;
import com.pervasive.project.unified.data.model.dto.CardInfoContainer;
import com.pervasive.project.unified.data.model.request.AddToHandRequest;
import com.pervasive.project.unified.data.model.request.DropCardRequest;
import com.pervasive.project.unified.data.model.request.QuitGameRequest;
import com.pervasive.project.unified.data.model.request.StartGameRequest;
import com.pervasive.project.unified.data.model.response.StartGameResponse;

 
@Path("/services")
public class Services {
	private static Map<Constants.cardId, Constants.cardStar> cardMap;
	private static MQTTConnection mqttConnection;
	private static Random random;
	
	@Context 
	ServletContext context;
	
	static{
		cardMap = new HashMap<Constants.cardId, Constants.cardStar>();
		mqttConnection = new MQTTConnection();
		random = new Random();

		System.out.println(" ==== Populating the MAP ==== ");
		// Calling a Temp Dummy Func to Populate the Card Mapping
		com.dummy.TempFunc.populateCardMap(cardMap);
	}
	
	/**
	 * This is just a Test Service 
	 * @param msg
	 * @return
	 */
	@GET
	@Path("/simpletext/{param}")
	public Response getMsg(@PathParam("param") String msg) {
 
		String output = "Jersey say : " + msg;
		System.out.println(" ============== Returning Output ============== ");
		
		return Response.status(200).entity(output).build();
 
	}
	
	/**
	 * This is Game Reset Service 
	 * @param msg
	 * @return
	 */
	@GET
	@Path("/gamereset")
	public Response gameReset() {
		cardMap.clear();
		com.dummy.TempFunc.populateCardMap(cardMap);
		
		GameContainer.getGameContainerInstance().cleanContainer();
		return Response.status(200).entity("OK").build();
 
	}
	
	@PUT
	@Path("/consumeAddToHandRequestService")
	public Response consumeImageService(String input)
	{
		// TEST STARTS
		System.out.println(" =========== Inside consumeAddToHandRequestService ============ ");
		// TEST ENDS
		
		Serializer serializer = new Persister();       
		Reader reader = new StringReader(input);
		AddToHandRequest addToHandRequest = new AddToHandRequest();
		try {
			addToHandRequest = serializer.read(AddToHandRequest.class, reader, false);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println(" =============== EXCEPTION ============== ");
			e.printStackTrace();
			return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Failed to Read Serialized Data").type(MediaType.TEXT_PLAIN).build();
		}
		
		// TEST STARTS
		System.out.println("UserName --> "+addToHandRequest.getUserName());
		System.out.println("Score --> "+addToHandRequest.getScore());
		// TEST ENDS
		
		String pixName = ((Integer)random.nextInt()).toString()+".jpeg";
		GameContainer.getGameContainerInstance().insertData(addToHandRequest.getUserName(), addToHandRequest.getCardName(), addToHandRequest.getScore(), pixName);
		
		// Step 1
		switch ( cardMap.get(addToHandRequest.getCardName()) )
		{
			case THREE:
				cardMap.put(addToHandRequest.getCardName(), Constants.cardStar.TWO);
				// Step 2
				mqttConnection.sendUpdate(addToHandRequest.getUserName()+","+addToHandRequest.getCardName().toString()+","+cardMap.get(addToHandRequest.getCardName()).toString());
				break;
			
			case TWO:
				cardMap.put(addToHandRequest.getCardName(), Constants.cardStar.ONE);
				// Step 2
				mqttConnection.sendUpdate(addToHandRequest.getUserName()+","+addToHandRequest.getCardName().toString()+","+cardMap.get(addToHandRequest.getCardName()).toString());
				break;
				
			case ONE:
				cardMap.put(addToHandRequest.getCardName(), Constants.cardStar.ZERO);
				// Step 2
				mqttConnection.sendUpdate(addToHandRequest.getUserName()+","+addToHandRequest.getCardName().toString()+","+cardMap.get(addToHandRequest.getCardName()).toString());
				break;
				
			case ZERO:
			default:
				break;
				
		}
		InputStream imageStream = new ByteArrayInputStream(addToHandRequest.getImageArray());
	    try {
			BufferedImage bufferedImage = ImageIO.read(imageStream);
			
			/* TODO:
			 * 1. Save the image using the UNIQUE File Name
			 */
			System.out.println("pixName --> "+pixName);
			ImageIO.write(bufferedImage, "jpg", new File(context.getRealPath("/")+"\\images\\snaps\\"+pixName));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println(" ===== Failed to interpret the image ===== ");
			e.printStackTrace();
			return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Failed to Interpret Image").type(MediaType.TEXT_PLAIN).build();
		}
	    
	    return Response.status(Response.Status.ACCEPTED).entity("Attachements processed successfully.").type(MediaType.TEXT_PLAIN).build();
	}
	
	@PUT
	@Path("/consumeDropCardRequestService")
	//@Produces(MediaType.TEXT_XML)
	public Response consumeDropCardRequestService(String input)
	{
		// TEST STARTS
		System.out.println(" =========== Inside consumeDropCardRequestService ============ ");
		// TEST ENDS
		
		Serializer serializer = new Persister();       
		Reader reader = new StringReader(input);
		DropCardRequest dropCardRequest = new DropCardRequest();
		try {
			dropCardRequest = serializer.read(DropCardRequest.class, reader, false);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println(" =============== EXCEPTION ============== ");
			e.printStackTrace();
			return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Failed to Read Serialized Data").type(MediaType.TEXT_PLAIN).build();
		}
		
		// TEST STARTS
		System.out.println("UserName --> "+dropCardRequest.getUserName());
		System.out.println("Card Name--> "+dropCardRequest.getCardName().toString());
		// TEST ENDS
		
		GameContainer.getGameContainerInstance().deleteData(dropCardRequest.getUserName(), dropCardRequest.getCardName());
		
		// Step 1
		switch ( cardMap.get(dropCardRequest.getCardName()) )
		{
			case THREE:
				cardMap.put(dropCardRequest.getCardName(), Constants.cardStar.THREE);
				// Step 2
				mqttConnection.sendUpdate(dropCardRequest.getUserName()+","+dropCardRequest.getCardName().toString()+","+cardMap.get(dropCardRequest.getCardName()).toString());
				break;
			
			case TWO:
				cardMap.put(dropCardRequest.getCardName(), Constants.cardStar.THREE);
				// Step 2
				mqttConnection.sendUpdate(dropCardRequest.getUserName()+","+dropCardRequest.getCardName().toString()+","+cardMap.get(dropCardRequest.getCardName()).toString());
				break;
				
			case ONE:
				cardMap.put(dropCardRequest.getCardName(), Constants.cardStar.TWO);
				// Step 2
				mqttConnection.sendUpdate(dropCardRequest.getUserName()+","+dropCardRequest.getCardName().toString()+","+cardMap.get(dropCardRequest.getCardName()).toString());
				break;
				
			case ZERO:
				cardMap.put(dropCardRequest.getCardName(), Constants.cardStar.ONE);
				// Step 2
				mqttConnection.sendUpdate(dropCardRequest.getUserName()+","+dropCardRequest.getCardName().toString()+","+cardMap.get(dropCardRequest.getCardName()).toString());
				break;
				
			default:
				break;
				
		}
	    
	    return Response.status(Response.Status.ACCEPTED).entity("Card Dropped successfully.").type(MediaType.TEXT_PLAIN).build();
	}
	
	@PUT
	@Path("/consumeStartGameRequestService")
	@Produces(MediaType.TEXT_XML)
	public String consumeStartGameRequestService(String input)
	{
		// TEST STARTS
		System.out.println(" =========== Inside consumeStartGameRequestService ============ ");
		// TEST ENDS
		
		Serializer serializer = new Persister();
		OutputStream outputStream = new ByteArrayOutputStream();
		
		Reader reader = new StringReader(input);
		StartGameRequest startGameRequest = new StartGameRequest();
		try {
			startGameRequest = serializer.read(StartGameRequest.class, reader, false);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println(" =============== EXCEPTION ============== ");
			e.printStackTrace();
			return "FAILED";
		}
		
		// TEST STARTS
		System.out.println("UserName --> "+startGameRequest.getName());
		// TEST ENDS
		
		StartGameResponse gameResponse = new StartGameResponse();
		
		List<CardInfoContainer> redOpen = new ArrayList<CardInfoContainer>();
		
		List<CardInfoContainer> redHand = new ArrayList<CardInfoContainer>();
		
		List<CardInfoContainer> blueOpen = new ArrayList<CardInfoContainer>();
		
		List<CardInfoContainer> blueHand = new ArrayList<CardInfoContainer>();
		
		List<CardInfoContainer> greenOpen = new ArrayList<CardInfoContainer>();
		
		List<CardInfoContainer> greenHand = new ArrayList<CardInfoContainer>();
		
		List<CardInfoContainer> yellowOpen = new ArrayList<CardInfoContainer>();
		
		List<CardInfoContainer> yellowHand = new ArrayList<CardInfoContainer>();
		
		if(GameContainer.getGameContainerInstance().getUserData().containsKey(startGameRequest.getName()))
		{
			Map<Constants.cardId, ContainerStruc> userData = GameContainer.getGameContainerInstance().getUserData().get(startGameRequest.getName());
			Iterator<Constants.cardId> userDataKeyIte = userData.keySet().iterator();
			
			while(userDataKeyIte.hasNext())
			{
				Constants.cardId eachCardId = userDataKeyIte.next();
				
				switch(eachCardId.getCardType())
				{
					case RED:
						redHand.add(new CardInfoContainer(eachCardId, cardMap.get(eachCardId), userData.get(eachCardId).getScore()));
						break;
						
					case BLUE:
						blueHand.add(new CardInfoContainer(eachCardId, cardMap.get(eachCardId), userData.get(eachCardId).getScore()));
						break;
						
					case GREEN:
						greenHand.add(new CardInfoContainer(eachCardId, cardMap.get(eachCardId), userData.get(eachCardId).getScore()));
						break;
						
					case YELLOW:
						yellowHand.add(new CardInfoContainer(eachCardId, cardMap.get(eachCardId), userData.get(eachCardId).getScore()));
						break;
					
					default:
						break;
				}
			}
		}
		
		Iterator<Constants.cardId> allCardIdIte = Arrays.asList(Constants.cardId.values()).iterator();
		Iterator<CardInfoContainer> handIte;
		boolean set;
		
		while(allCardIdIte.hasNext())
		{
			Constants.cardId eachCardId = allCardIdIte.next();
			
			switch(eachCardId.getCardType())
			{
				case RED:
					handIte = redHand.iterator();
					set = false;
					while(handIte.hasNext())
					{
						CardInfoContainer eachCardInfoContainer = handIte.next();
						if(eachCardInfoContainer.getCardId() == eachCardId)
						{
							set = true;
							break;
						}
					}
					
					if(!set)
					{
						redOpen.add(new CardInfoContainer(eachCardId, cardMap.get(eachCardId)));
					}
					
					break;
					
				case BLUE:
					handIte = blueHand.iterator();
					set = false;
					while(handIte.hasNext())
					{
						CardInfoContainer eachCardInfoContainer = handIte.next();
						if(eachCardInfoContainer.getCardId() == eachCardId)
						{
							set = true;
							break;
						}
					}
					
					if(!set)
					{
						blueOpen.add(new CardInfoContainer(eachCardId, cardMap.get(eachCardId)));
					}
					
					break;
					
				case GREEN:
					handIte = greenHand.iterator();
					set = false;
					while(handIte.hasNext())
					{
						CardInfoContainer eachCardInfoContainer = handIte.next();
						if(eachCardInfoContainer.getCardId() == eachCardId)
						{
							set = true;
							break;
						}
					}
					
					if(!set)
					{
						greenOpen.add(new CardInfoContainer(eachCardId, cardMap.get(eachCardId)));
					}
					
					break;
					
				case YELLOW:
					handIte = yellowHand.iterator();
					set = false;
					while(handIte.hasNext())
					{
						CardInfoContainer eachCardInfoContainer = handIte.next();
						if(eachCardInfoContainer.getCardId() == eachCardId)
						{
							set = true;
							break;
						}
					}
					
					if(!set)
					{
						yellowOpen.add(new CardInfoContainer(eachCardId, cardMap.get(eachCardId)));
					}
					
					break;
				
				default:
					break;
			}
		}
		
		gameResponse.setRedOpen(redOpen);
		gameResponse.setBlueOpen(blueOpen);
		gameResponse.setGreenOpen(greenOpen);
		gameResponse.setYellowOpen(yellowOpen);
		
		gameResponse.setRedHand(redHand);
		gameResponse.setBlueHand(blueHand);
		gameResponse.setGreenHand(greenHand);
		gameResponse.setYellowHand(yellowHand);
		
		gameResponse.setMinute(10);
		gameResponse.setSeconds(0);
		
		// TODO:: Return the Response
	   // return Response.status(Response.Status.ACCEPTED).entity("Card Dropped successfully.").type(MediaType.TEXT_PLAIN).build();
		
		try {
			serializer.write(gameResponse, outputStream);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("returning --> "+outputStream.toString());
		return outputStream.toString();
	}
	
	// Experimental
	
	/*@PUT
	@Path("/consumeQuitGameRequestService")
	//@Produces(MediaType.TEXT_XML)
	public Response consumeQuitGameRequestService(String input)
	{
		// TEST STARTS
		System.out.println(" =========== Inside consumeDropCardRequestService ============ ");
		// TEST ENDS
		
		Serializer serializer = new Persister();       
		Reader reader = new StringReader(input);
		QuitGameRequest quitGameRequest = new QuitGameRequest();
		try {
			quitGameRequest = serializer.read(QuitGameRequest.class, reader, false);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println(" =============== EXCEPTION ============== ");
			e.printStackTrace();
			return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Failed to Read Serialized Data").type(MediaType.TEXT_PLAIN).build();
		}
		
		// TEST STARTS
		System.out.println("UserName --> "+quitGameRequest.getName());
		// TEST ENDS
		
		//Time t1;
		System.currentTimeMillis();
		Date d1 = new Date();
		d1.gett
	    
	    return Response.status(Response.Status.ACCEPTED).entity("Card Dropped successfully.").type(MediaType.TEXT_PLAIN).build();
	}*/
}